/******************************************************************
*
* CyberHTTP for Java
*
* Copyright (C) Satoshi Konno 2002
*
* File: HTTPRequest.java
*
******************************************************************/

package com.cidero.http;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.logging.Logger;

import com.cidero.util.BufferedReaderInputStream;

/**
 *  HTTP request class.  This class is used for HTTP clients as well as
 *  servers.
 *
 */
public class HTTPRequest extends HTTPPacket
{
  private static Logger logger = Logger.getLogger("com.cidero.http");

  // Request line elements
  private String method = null;
  private String resource = null;
  private String version = null;

  private int    port = HTTP.DEFAULT_PORT;
  private String host = null;
  
  private URL    url = null;
  
  HTTPConnection connection = null;

  /**
   * Constructor for outgoing requests (client-side)
   *
   * @param method   Method for request (GET,POST,etc...)
   * @param url      URL for method ('http:/<host>.<port>/path')
   *  
   */
  public HTTPRequest( String method, URL url )
  {
    this.method = method;

    //logger.info("URL Path: " + url.getPath() + " Query: " + url.getQuery() );
    
    if( url.getQuery() != null )
      this.resource = url.getPath() + "?" + url.getQuery();
    else
      this.resource = url.getPath();

    if( resource == null || resource == "" )
      resource = "/";
    
    this.version = HTTP.VERSION;

    this.host = url.getHost();
    if( url.getPort() != -1 )
      this.port = url.getPort();

    this.url = url;
  }

  /**
   * Constructor for incoming requests (server-side)
   *
   * @param connection   Connection to use to read the incoming request
   *  
   */
  public HTTPRequest( HTTPConnection connection )
    throws IOException
  {
    this( connection, true );
  }
  
  /**
   * Constructor for incoming requests (server-side)
   *
   * @param connection   Connection to use to read the incoming request
   *  
   */
  public HTTPRequest( HTTPConnection connection, boolean getContent )
    throws IOException
  {
    this.connection = connection;
    
    BufferedReaderInputStream inputStream = connection.getInputStream();
    
    String firstLine = inputStream.readLine();
    if( firstLine == null )
      throw new IOException("zero-length HTTP request" );

    setFirstLine( firstLine );
    if (! parseRequestLine( firstLine ))
      throw new IOException("Bad request line: '" + firstLine + "'" );

    readHeaderLines( inputStream );
    if( getContent )
      readContent( inputStream );
  }

  public HTTPConnection getConnection()
  {
    return connection;
  }

  
  /**
   *  Set request method (HTTP.GET, HTTP.POST, etc..). 
   *  (client side)
   */
  public void setMethod(String value)
  {
    method = value;
  }
  public String getMethod()
  {
    return method;
  }

  public int getPort()
  {
    return port;
  }
  public String getHost()
  {
    return host;
  }
  



  public boolean isMethod(String methodName)
  {
    if (method == null)
      return false;
    return method.equalsIgnoreCase( methodName );
  }

  public boolean isGetRequest()
  {
    return isMethod(HTTP.GET);
  }

  public boolean isHeadRequest()
  {
    return isMethod(HTTP.HEAD);
  }

  public boolean isPostRequest()
  {
    return isMethod(HTTP.POST);
  }

  public boolean isSubscribeRequest()
  {
    return isMethod(HTTP.SUBSCRIBE);
  }

  public boolean isUnsubscribeRequest()
  {
    return isMethod(HTTP.UNSUBSCRIBE);
  }

  public boolean isNotifyRequest()
  {
    return isMethod(HTTP.NOTIFY);
  }
 

  public void setResource(String resource)
  {
    this.resource = resource;
  }

  public String getResource()
  {
    return resource;
  }

  ////////////////////////////////////////////////
  //  Version
  ////////////////////////////////////////////////


  public void setVersion(String value)
  {
    version = value;
  }
    
  public String getVersion()
  {
    return version;
  }

  /**
   *  Check if request is a SOAP action
   *
   */
  public boolean isSOAPAction()
  {
    return hasHeader(HTTP.SOAP_ACTION);
  }

  ////////////////////////////////////////////////
  // Host / Port  
  ////////////////////////////////////////////////
  
  private String requestHost = "";
  
  public void setRequestHost(String host)
  {
    requestHost = host;
  }

  public String getRequestHost()
  {
    return requestHost;
  }

  private int requestPort = -1;
  
  public void setRequestPort(int host)
  {
    requestPort = host;
  }

  public int getRequestPort()
  {
    return requestPort;
  }
  
  /**
   *  Get local address of HTTP request socket
   */
  /*
  public String getLocalAddress()
  {
    return getSocket().getLocalAddress(); 
  }
  */
  /**
   *  Get local port of HTTP request socket
   */
  /*
  public int getLocalPort()
  {
    return getSocket().getLocalPort();  
  }
  */

  /** 
   * Parse HTTP request line. Request line syntax is:
   *  
   *  <method> <URI> <HTTPVersion>
   *
   * Example:
   * 
   *  GET /dir/file HTTP/1.0  
   *
   * @param  lineStr    Request line (1st line in HTTP request)
   */
  public boolean parseRequestLine(String lineStr)
  {
    StringTokenizer st = new StringTokenizer(lineStr, HTTP.REQEST_LINE_DELIM);
    if (st.hasMoreTokens() == false)
      return false;
    setMethod(st.nextToken());
    if (st.hasMoreTokens() == false)
      return false;
    setResource(st.nextToken());
    if (st.hasMoreTokens() == false)
      return false;
    setVersion(st.nextToken());
    return true;
  }

  /**
   *  Construct a header string from the fields in the status object
   *
   *  @return   HTTP request header block ( "GET /file HTTP/1.0" )
   */
  public String getHeaderString()
  {
    StringBuffer str = new StringBuffer();
    
    str.append( method + " " + resource + " HTTP/" + version + HTTP.CRLF );
    str.append( getAllHeaderLinesAsString() );
    str.append( HTTP.CRLF );   // Add blank line   
    return str.toString();
  }
  
  /**
   * Convenience routines to return simple responses with a given status code.
   */
  public void returnResponse(int statusCode)
  {
    HTTPResponse httpRes = new HTTPResponse();
    httpRes.setStatusCode(statusCode);
    httpRes.setContentLength(0);
    try
    {
      connection.sendResponse( httpRes );
    }
    catch( IOException e )
    {
      logger.warning("Error sending response" + e );
    }
    
  }

  /**
   * Convenience routine to return a response with an OK status code.
   */
  public void returnOK()
  {
    returnResponse(HTTPStatus.OK);
  }

  /**
   * Convenience routine to return a response with a BAD REQUEST status code.
   */
  public void returnBadRequest()
  {
    returnResponse(HTTPStatus.BAD_REQUEST);
  }

}
